import {BaseSession} from "./base";
import {fromAny, toAny, StringValue, BoolValue, Int32Value} from "../proto"

export class SoundPoolSession extends BaseSession {
    private players: HTMLAudioElement[] = null;
    private urls: Map<string, string> = null;
    private playIdx = 0;
    constructor(render: HTMLElement) {
        super('SoundPool', render);
    }

    onCreate(sessionId: number, futureId: number, ...argv) {
        super.onCreate(sessionId, futureId, ...argv);
        const poolSize: number = (argv && argv.length > 0) ? fromAny(argv[0], Int32Value) : 5
        this.urls = new Map<string, string>()
        this.players = [];
        for (let i = 0; i < poolSize; i++)
            this.players.push(document.createElement('audio'))
    }

    onDestroy() {
        this.players.forEach(p => {
            p.pause()
            p.removeAttribute('src')
        })
        this.players = null;
        super.onDestroy();
    }

    async onReceive(name: String, sessionId: number, futureId: number, ...argv) {
        switch (name) {
            case 'load':
                return this.load(sessionId, futureId, ...argv)
            case 'play':
                return this.play(sessionId, futureId, ...argv)
            case 'stop':
                return this.stop(...argv)
            default:
                return super.onReceive(name, sessionId, futureId, ...argv);
        }
    }
    private load(sessionId: number, futureId: number, ...argv) {
        const baseUrl = fromAny(argv[0], StringValue)
        for (let i = 1; i < argv.length; i++) {
            const path = fromAny(argv[i], StringValue)
            if (!this.urls.has(path))
                this.urls[path] = baseUrl
        }
        this.sendAction('onLoad', sessionId, futureId, toAny(true, BoolValue))
    }
    private async play(sessionId: number, futureId: number, ...argv) {
        const path = fromAny(argv[0], StringValue)
        const baseUrl = this.urls[path]
        let player = this.players.find(p => p.getAttribute('src')==null)
        if (!player)
            player = this.players.find(p => p.paused)
        if (!player) {
            player = this.players[0]
            player.removeAttribute('src')
        }
        player.setAttribute('src', baseUrl + path)
        const onended = () => {
            player.removeAttribute('src')
            player.removeEventListener("ended", onended)
        }
        player.addEventListener('ended', onended)
        try {
            await player.play()
            player.setAttribute('playId', (this.playIdx++).toString())
            this.sendAction('onPlay', sessionId, futureId, toAny(this.playIdx, Int32Value))
        } catch (e) {
            this.onError(e, sessionId, futureId)
        }
    }
    private stop(...argv) {
        const playId: number = fromAny(argv[0], Int32Value)
        const player =  this.players.find(p => p.getAttribute('playId') == playId.toString())
        if (player)
            player.paused
    }
}